#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:John Zhou
# Time:2022年05月20日
import sys
from PCANBasic import *        ## PCAN-Basic library import
import PyQt5.QtWidgets as qw
from PyQt5.QtWidgets import QApplication,QPushButton, QWidget, QTableWidgetItem,QTreeWidgetItem, QTreeWidget, QMainWindow
import threading
from PyQt5.QtCore import QThread, pyqtSignal, QTimer, QObject
from PCANToolUI import *
import win32event
from udsoncan.client import Client
import udsoncan
from udsoncan.connections import BaseConnection,PythonIsoTpConnection
from udsoncan import services, Response, MemoryLocation
import isotp
import time
from can.interfaces.pcan.pcan import PcanBus
from udsoncan.services import *
import udsoncan.configs
import binascii
from hexhanle import HexHandle

ecuXorArray =[0x47,0x53,0x4D,0x4B]

EGSM_TX_ID = 0x7F0
EGSM_RX_ID_PHYS = 0x784
EGSM_RX_ID_FUNC = 0x7FF
FLASH_DRIVER_ADDRESS = 0x20004000
APP_ADDRESS = 0X8000

class myMainWindow(QMainWindow,Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.DeviceInit()
        self.REFRESH_VALUE = 0
        # self.myTimer()

        # 绑定信号与槽
        self.actionChannel01.triggered.connect(self.actionChannel01_cb)       # 连接通道1
        self.btn_openAPP.clicked.connect(self.btn_openAPP_cb)                # 打开APP
        self.btn_openFlash.clicked.connect(self.btn_openFlash_cb)            # 打开Flash Driver
        self.btn_update.clicked.connect(self.btn_update_cb)                  # 软件升级
        self.btn_clearMsg.clicked.connect(self.btn_clearDTC_cb)              # 清除显示文本
    # 界面及参数初始化
    def DeviceInit(self):
        self.m_objPCANBasic = PCANBasic()
        self.m_PcanHandle = PCAN_USBBUS1
        self.m_CanRead = False
        self.m_ReadThread = None
        self.m_Terminated = False
        self._lock = threading.RLock()
        self.m_ReceiveEvent = win32event.CreateEvent(None, 0, 0, None)
        # bManualReset(参数2)：[输入]指定将事件对象创建成手动复原还是自动复原。如果是TRUE，那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。
        # 如果设置为FALSE，当事件被一个等待线程释放以后，系统将会自动将事件状态复原为无信号状态。
        # bInitialState（参数3）：[输入]指定事件对象的初始状态。如果为TRUE，初始状态为有信号状态；否则为无信号状态。
        self.isCh1Open = False
        self.isCh1HasMes = False
        self.is_extendMode = False
        self.is_L61 = False

        self.refresh_Thread = refresh_APP_Thread()

    # 连接通道1
    def actionChannel01_cb(self):
        content = self.actionChannel01.text()
        print(content)
        try:
            if content == "连接PCAN通道1":
                if(self.refresh_Thread.start_client()):
                    # Prepares the PCAN-Basic's PCAN-Trace file
                    self.isCh1Open = True
                    print("通道1已连接")
                    self.tb_message.setText("提示：通道1已连接！")
                    self.tb_message.ensureCursorVisible()
                    self.tb_message.moveCursor(self.tb_message.textCursor().End)
                    self.actionChannel01.setText("释放PCAN通道1")
                else:
                    print("CAN Initial Error!")
                    self.tb_message.setText("提示：通道1连接失败！")
                    self.tb_message.ensureCursorVisible()
                    self.tb_message.moveCursor(self.tb_message.textCursor().End)
            else:
                # Releases a current connected PCAN-Basic channel
                if self.refresh_Thread.connection.is_open():
                    self.connection.close()

                result = self.m_objPCANBasic.Uninitialize(PCAN_USBBUS1)
                if result != PCAN_ERROR_OK:
                    # An error occurred, get a text describing the error and show it
                    #
                    print("Error!", self.GetFormatedError(result))
                else:
                    self.isCh1Open = False
                    print("通道1已释放")
                    self.tb_message.ensureCursorVisible()
                    self.tb_message.setText("提示：通道1已释放！")
                    self.actionChannel01.setText("连接PCAN通道1")
                    # self.lineEditFlash.clear()
                    # self.lineEditAPP.clear()
                    self.progressBar.setValue(0)
        except Exception as err:
            print(err)

#---------------------------------------------------------------------------------------#
    # 清空显示在界面上的信息
    def btn_clearDTC_cb(self):
        self.tb_message.clear()
        self.tb_message.moveCursor(self.tb_message.textCursor().End)

    # ------------------------------------------------------------------------------------- #
    # 刷新程序
    def btn_update_cb(self):
        if self.isCh1Open:
            if self.lineEditAPP.text() != "" and self.lineEditFlash.text() != "":
                print("新建刷新线程")
                # self.refresh_Thread = refresh_APP_Thread()
                print("线程参数传递")
                self.refresh_Thread.value_signal.connect(self.update_counts)
                self.refresh_Thread.message_signal.connect(self.update_message_show)
                print("开启刷新线程")
                self.refresh_Thread.start()
            else:
                print("请加载FlashDriver和APP软件")
                self.tb_message.append("提示：请加载FlashDriver和APP软件！")
                self.tb_message.ensureCursorVisible()
                self.tb_message.moveCursor(self.tb_message.textCursor().End)
        else:
            print("通道未连接！")
            self.tb_message.append("提示：通道未连接！")
            self.tb_message.ensureCursorVisible()
            self.tb_message.moveCursor(self.tb_message.textCursor().End)

    # 更新进度条（自定义信号）
    def update_counts(self, int):
        self.progressBar.setValue(int)

    # 更新输出内容（自定义信号）
    def update_message_show(self, str):
        self.tb_message.append(str)
        self.tb_message.ensureCursorVisible()
        self.tb_message.moveCursor(self.tb_message.textCursor().End)

    # 打开APP文件
    def btn_openAPP_cb(self):
        global AppPath
        FilePath = QtWidgets.QFileDialog.getOpenFileName(self, "选取APP文件", "./", "All Files (*);;Text Files (*.txt)")
        AppPath = FilePath[0]
        self.lineEditAPP.setText(AppPath)
        return AppPath

    # 打开flash文件
    def btn_openFlash_cb(self):
        global FlashPath
        FilePath = QtWidgets.QFileDialog.getOpenFileName(self, "选取Flash Driver文件", "./", "All Files (*);;Text Files (*.txt)")
        FlashPath = FilePath[0]
        self.lineEditFlash.setText(FlashPath)
        return FlashPath

# ------------------------------------------------------------------------------------- #
# 软件刷新线程
class refresh_APP_Thread(QThread):
    value_signal = pyqtSignal(int)
    message_signal = pyqtSignal(str)
    flash_path = pyqtSignal(str)
    app_path = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        # self.value = value
        self.m_objPCANBasic = PCANBasic()
        self.m_PcanHandle = PCAN_USBBUS1
        self.isotp_params = {
            'stmin': 1,                          # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9.流控帧间隔时间，0-127ms 或 100-900ns 值从 0xF1-0xF9
            'blocksize': 8,                       # Request the sender to send 8 consecutives frames before sending a new flow control message.流控帧单包大小，0表示不限制
            'wftmax': 0,                          # Number of wait frame allowed before triggering an error
            'tx_data_length': 8,                  # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
            'tx_padding': 0,                      # Will pad all transmitted CAN messages with byte 0x00. None means no padding. 当 notNone表示用于填充发送的消息的字节
            'rx_flowcontrol_timeout': 1000,        # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds.在停止接收和触发之前等待流控制帧的毫秒数
            'rx_consecutive_frame_timeout': 1000,  # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds. 在停止接收和触发 a 之前等待连续帧的毫秒数
            'squash_stmin_requirement': True     # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
            }

    def start_client(self):
        try:
            self.canbus = PcanBus(channel='PCAN_USBBUS1', bitrate=500000)  # CAN总线初始化
            result = self.m_objPCANBasic.GetStatus(PCAN_USBBUS1)
            print("通讯盒连接状态",result)
            if result == PCAN_ERROR_OK:
                self._isotpaddr_PHYS = isotp.Address(isotp.AddressingMode.Normal_11bits, txid=EGSM_RX_ID_PHYS, rxid=EGSM_TX_ID)  # 网络层寻址方法
                self.tp_stack = isotp.CanStack(bus=self.canbus, address=self._isotpaddr_PHYS,
                                               params=self.isotp_params)  # 网络/传输层（IsoTP 协议）
                self.connection = PythonIsoTpConnection(self.tp_stack)  # 应用层和传输层之间建立连接

                self.config1 = dict(udsoncan.configs.default_client_config)
                self.config1['security_algo'] = self.SecAlgo
                self.config1['security_algo_params'] = dict(INITIAL_REMINDER=0xFFFE)
                self.config1['data_identifiers'] = {
                    0xFD09: udsoncan.DidCodec('B'),  # switch
                    0xCF01: udsoncan.DidCodec('B'),  # shift lever position
                    0xF15A: udsoncan.DidCodec('BBBBBBBBB'),
                    # Codec that read ASCII string. We must tell the length of the string
                    0xF193: udsoncan.AsciiCodec(10),  # HW version
                    0xF195: udsoncan.AsciiCodec(10),  # SW Version
                    0xF187: udsoncan.AsciiCodec(20),  # Spare part No.
                    0xF18A: udsoncan.AsciiCodec(10),  # sys supplier
                    0xF18C: udsoncan.AsciiCodec(10),  # ECU Serial No.
                    0xF190: udsoncan.AsciiCodec(17),  # VIN
                    0xF180: udsoncan.AsciiCodec(10)  # Bootloader version
                }
                self.config1['server_address_format'] = 32
                self.config1['server_memorysize_format'] = 32
                self.config1['standard_version'] = 2006
                self.config1['request_timeout'] = 5
                self.config1['p2_timeout'] = 5

                udsoncan.setup_logging()#logging.conf, add by zhangwk, 240428 

                with Client(self.connection, config=self.config1, request_timeout=2) as self.uds_client:
                    self.connection.open()  # 打开连接
                    print(self.connection.is_open())
                    return 1
            else:
                print("通道未连接！")
                return 0

        except Exception as err:
            print(err)

    #安全算法
    def SecAlgo(self, level, seed):
        bSeed = seed
        Cal = []
        Key = [0,0,0,0]
        # InitialReminder = params['INITIAL_REMINDER']
        if level == 0x03:
            for i in range (4):
                Cal.append(bSeed[i] ^ ecuXorArray[i])
            Key[0] = (((Cal[2] & 0xF0) << 4) | (Cal[3] & 0xF0))&0xFF
            Key[1] = (((Cal[3] & 0x2F) << 2) | (Cal[1] & 0x03))&0xFF
            Key[2] = (((Cal[1] & 0xFC) >> 2) | (Cal[0] & 0xC0))&0xFF
            Key[3] = (((Cal[0] & 0x0F) << 4) | (Cal[2] & 0x0F))&0xFF
            remainder = (Key[0]<<24)+(Key[1]<<16)+(Key[2]<<8)+Key[3]
            output_key = (remainder).to_bytes(4, 'big', signed=False)

        elif level == 0x09:
            print("进入09")
            for i in range(4):
                Cal.append(bSeed[i] ^ ecuXorArray[i])
            Key[0] = (((Cal[1] & 0x7F) << 2) | (Cal[2] & 0xF0))&0xFF
            Key[1] = (((Cal[0] & 0xEC) >> 2) | (Cal[1] & 0x7E))&0xFF
            Key[2] = (((Cal[3] & 0xF0) >> 4) | (Cal[0] & 0x2C))&0xFF
            Key[3] = (((Cal[2] & 0x0F) << 4) | (Cal[3] & 0x7d))&0xFF
            remainder = (Key[0] << 24) + (Key[1] << 16) + (Key[2] << 8) + Key[3]
            output_key = (remainder).to_bytes(4, 'big', signed=False)
        return output_key

    # crc16校验
    def Calculate_CRC16(self, size, pdata):
        crctab =[0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
                 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
                 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
                 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
                 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
                 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
                 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
                 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
                 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
                 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
                 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
                 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
                 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
                 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
                 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
                 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0]
        crc = 0xFFFF
        for i in range(size):
            tmp = (crc >> 8) ^ pdata[i]
            # print("tmp",tmp)
            crc = ((crc << 8)&(0xFFFF)) ^ crctab[tmp]
            # print("crc",crc)
        return crc
    def Calculate_CRC16_DNP(self, size, pdata):
        crctab =[  0x0000, 0x365e, 0x6cbc, 0x5ae2, 0xd978, 0xef26, 0xb5c4, 0x839a,
                    0xff89, 0xc9d7, 0x9335, 0xa56b, 0x26f1, 0x10af, 0x4a4d, 0x7c13,
                    0xb26b, 0x8435, 0xded7, 0xe889, 0x6b13, 0x5d4d, 0x07af, 0x31f1,
                    0x4de2, 0x7bbc, 0x215e, 0x1700, 0x949a, 0xa2c4, 0xf826, 0xce78,
                    0x29af, 0x1ff1, 0x4513, 0x734d, 0xf0d7, 0xc689, 0x9c6b, 0xaa35,
                    0xd626, 0xe078, 0xba9a, 0x8cc4, 0x0f5e, 0x3900, 0x63e2, 0x55bc,
                    0x9bc4, 0xad9a, 0xf778, 0xc126, 0x42bc, 0x74e2, 0x2e00, 0x185e,
                    0x644d, 0x5213, 0x08f1, 0x3eaf, 0xbd35, 0x8b6b, 0xd189, 0xe7d7,
                    0x535e, 0x6500, 0x3fe2, 0x09bc, 0x8a26, 0xbc78, 0xe69a, 0xd0c4,
                    0xacd7, 0x9a89, 0xc06b, 0xf635, 0x75af, 0x43f1, 0x1913, 0x2f4d,
                    0xe135, 0xd76b, 0x8d89, 0xbbd7, 0x384d, 0x0e13, 0x54f1, 0x62af,
                    0x1ebc, 0x28e2, 0x7200, 0x445e, 0xc7c4, 0xf19a, 0xab78, 0x9d26,
                    0x7af1, 0x4caf, 0x164d, 0x2013, 0xa389, 0x95d7, 0xcf35, 0xf96b,
                    0x8578, 0xb326, 0xe9c4, 0xdf9a, 0x5c00, 0x6a5e, 0x30bc, 0x06e2,
                    0xc89a, 0xfec4, 0xa426, 0x9278, 0x11e2, 0x27bc, 0x7d5e, 0x4b00,
                    0x3713, 0x014d, 0x5baf, 0x6df1, 0xee6b, 0xd835, 0x82d7, 0xb489,
                    0xa6bc, 0x90e2, 0xca00, 0xfc5e, 0x7fc4, 0x499a, 0x1378, 0x2526,
                    0x5935, 0x6f6b, 0x3589, 0x03d7, 0x804d, 0xb613, 0xecf1, 0xdaaf,
                    0x14d7, 0x2289, 0x786b, 0x4e35, 0xcdaf, 0xfbf1, 0xa113, 0x974d,
                    0xeb5e, 0xdd00, 0x87e2, 0xb1bc, 0x3226, 0x0478, 0x5e9a, 0x68c4,
                    0x8f13, 0xb94d, 0xe3af, 0xd5f1, 0x566b, 0x6035, 0x3ad7, 0x0c89,
                    0x709a, 0x46c4, 0x1c26, 0x2a78, 0xa9e2, 0x9fbc, 0xc55e, 0xf300,
                    0x3d78, 0x0b26, 0x51c4, 0x679a, 0xe400, 0xd25e, 0x88bc, 0xbee2,
                    0xc2f1, 0xf4af, 0xae4d, 0x9813, 0x1b89, 0x2dd7, 0x7735, 0x416b,
                    0xf5e2, 0xc3bc, 0x995e, 0xaf00, 0x2c9a, 0x1ac4, 0x4026, 0x7678,
                    0x0a6b, 0x3c35, 0x66d7, 0x5089, 0xd313, 0xe54d, 0xbfaf, 0x89f1,
                    0x4789, 0x71d7, 0x2b35, 0x1d6b, 0x9ef1, 0xa8af, 0xf24d, 0xc413,
                    0xb800, 0x8e5e, 0xd4bc, 0xe2e2, 0x6178, 0x5726, 0x0dc4, 0x3b9a,
                    0xdc4d, 0xea13, 0xb0f1, 0x86af, 0x0535, 0x336b, 0x6989, 0x5fd7,
                    0x23c4, 0x159a, 0x4f78, 0x7926, 0xfabc, 0xcce2, 0x9600, 0xa05e,
                    0x6e26, 0x5878, 0x029a, 0x34c4, 0xb75e, 0x8100, 0xdbe2, 0xedbc,
                    0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235]
        crc = 0X0
        for i in range(size):
            tmp = (crc ^ pdata[i]) & 0xff
            # print("tmp",tmp)
            crc = ((crc >> 8)&(0xFFFF)) ^ crctab[tmp]
            # print("crc",crc)
        crcResult = ((~crc) & 0xFFFF);
        return crcResult
    # crc32校验
    def Calculate_CRC32(self, size, pdata):
        crctab =[0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
                    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
                    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
                    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
                    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
                    0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
                    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
                    0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
                    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
                    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
                    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
                    0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
                    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
                    0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
                    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
                    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
                    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
                    0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
                    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
                    0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
                    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
                    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
                    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
                    0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
                    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
                    0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
                    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
                    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
                    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
                    0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
                    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
                    0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
                    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
                    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
                    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
                    0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
                    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
                    0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
                    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
                    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
                    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
                    0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
                    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
                    0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
                    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
                    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
                    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
                    0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
                    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
                    0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
                    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
                    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
                    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
                    0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
                    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
                    0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
                    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
                    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
                    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
                    0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
                    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
                    0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
                    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
                    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]
        crc = 0xFFFFFFFF
        for i in range(size):
            # print("i={},pdata[i]=".format(i,pdata[i]))
            tmp = (crc ^ pdata[i]) & 0xFF
            # print("tmp",tmp)
            crc = ((crc >> 8)&(0xFFFFFF)) ^ crctab[tmp]
            # print("crc",crc)
        crc = (crc ^ 0xFFFFFFFF)
        return crc

    # 获取hex文件大小
    def getFileSize(self, filePath):
        fileSize = 0
        try:
            with open(filePath,'r') as f:
                linelist = f.readlines()
                for line in linelist:
                    if int(line[8]) == 0:                   # 判断该行是否为数据
                        fileSize += int(line[1:3],base=16)  # 如果是数据行则提取第1、2位（表示改行数据长度），并将str转换为16进制
                print("fileSize",fileSize)
            # fileSize = os.path.getsize(filePath)
            return fileSize
        except Exception as err:
            print(err)

    # 获取hex文件数据长度和首地址
    def getFileSizeAndAddress(self, filePath):
        fileSize = 0
        try:
            with open(filePath,'r') as f:
                linelist = f.readlines()
                startAddress = int(linelist[1][3:7], base=16)
                for line in linelist:
                    if int(line[8]) == 0:                   # 判断该行是否为数据
                        fileSize += int(line[1:3], base=16)  # 如果是数据行则提取第1、2位（表示改行数据长度），并将str转换为16进制
                print("fileSize,startAddress", fileSize, startAddress)
            # fileSize = os.path.getsize(filePath)
            return fileSize, startAddress
        except Exception as err:
            print(err)


    # 获取hex文件内容
    def getFileContent(self,filePath):
        lineData = ''
        try:
            with open(filePath,'r') as f:
                linelist = f.readlines()
                for line in linelist:
                    if int(line[8]) == 0:
                        lineDataSize = int(line[1:3],base=16)
                        lineData += line[9:-3]
                fileContent = binascii.a2b_hex(lineData)        # 字符串转换为bytes格式
            return fileContent
        except Exception as err:
            print(err)

    # 获取hex文件内容
    def getFileContentInt(self, filePath):
        fileContent = []
        try:
            with open(filePath, 'r') as f:
                linelist = f.readlines()
                for line in linelist:
                    if int(line[8]) == 0:
                        lineDataSize = int(line[1:3], base=16)
                        # print("lineDataSize",lineDataSize)
                        lineData = line[9:-2]
                        # print("lineData",lineData)
                        for i in range(lineDataSize):
                            fileContent.append(int(lineData[2*i:(2*i+2)],base=16))

            return fileContent
        except Exception as err:
            print(err)

    def run(self):
        print("运行刷写线程")
        try:
            print("开启服务")
            self.start_client()
            if not self.connection.is_open():
                self.connection.open()
            # I：刷新准备阶段
            print("开始刷新，准备阶段")
            tbMessage = "软件刷写：开始软件刷新"
            self.message_signal.emit(tbMessage)
            # a:进入扩展模式
            tbMessage = "软件刷写：刷新准备阶段-进入扩展模式"
            self.message_signal.emit(tbMessage)
            self.uds_client.change_session(1)
            self.uds_client.change_session(3)
            self.REFRESH_VALUE = 5
            self.value_signal.emit(self.REFRESH_VALUE)

            #检查预编程条件
            # tbMessage = "软件刷写：刷新准备阶段-预编程条件检查"
            # self.message_signal.emit(tbMessage)
            # self.uds_client.start_routine(routine_id=0x0203)
            # self.REFRESH_VALUE = 8
            # self.value_signal.emit(self.REFRESH_VALUE)

            # b:关闭DTC
            tbMessage = "软件刷写：刷新准备阶段-停止DTC检出"
            self.message_signal.emit(tbMessage)
            self.uds_client.control_dtc_setting(services.ControlDTCSetting.SettingType.off)
            self.REFRESH_VALUE = 10
            self.value_signal.emit(self.REFRESH_VALUE)

            # c:停止非诊断报文
            tbMessage = "软件刷写：刷新准备阶段-停止非诊断报文收发"
            self.message_signal.emit(tbMessage)
            self.uds_client.communication_control(0x3, 0x3)
            self.REFRESH_VALUE = 15
            self.value_signal.emit(self.REFRESH_VALUE)

            # II:刷新阶段，下载数据
            print("开始刷新，下载数据")
            # a:进入编程会话
            tbMessage = "软件刷写：下载数据阶段-进入编程会话"
            self.message_signal.emit(tbMessage)
            self.uds_client.change_session(2)
            self.REFRESH_VALUE = 17
            self.value_signal.emit(self.REFRESH_VALUE)

            # b:安全访问服务
            tbMessage = "软件刷写：下载数据阶段-安全访问服务"
            self.message_signal.emit(tbMessage)
            self.uds_client.unlock_security_access(9)
            self.REFRESH_VALUE = 20
            self.value_signal.emit(self.REFRESH_VALUE)
            time.sleep(0.5)

            # d:request flash driver download to RAM
            print("请求下载FlashDriver。")
            tbMessage = "软件刷写：下载数据阶段-请求下载FlashDriver"
            self.message_signal.emit(tbMessage)
            print("FlashPath=",FlashPath)
            # 获取flash driver的起始地址大小
            flashDriverHex = HexHandle(FlashPath)
            flashDriverHexInfo = flashDriverHex.get_res()
            flashDriverStartAddress = flashDriverHexInfo["start_index"]
            flashDriverSize = flashDriverHexInfo["data_length"]
            FlashML = MemoryLocation(address=flashDriverStartAddress, memorysize=flashDriverSize)  # flash driver的大小和地址
            print("flashDriverStartAddress:{},flashDriverSize:{}".format(flashDriverStartAddress,flashDriverSize))
            flashDriverContent = self.getFileContent(FlashPath)                            # 获取flash driver的内容
            # print("flashDriverContent",flashDriverContent)
            resp_flash = self.uds_client.request_download(memory_location=FlashML)                   # 请求下载0x34
            # _maxNumOfBlockLen = ((resp_flash.data[1] << 8) | (resp_flash.data[2] & 0xFF))               # 获取每次能传输的最大字节
            _maxNumOfBlockLen = 0x80 #zhangwk 
            _blockSequenceCounter = 1
            self.REFRESH_VALUE = 22
            self.value_signal.emit(self.REFRESH_VALUE)

            print("开始传输Flash Driver数据。")
            tbMessage = "软件刷写：下载数据阶段-下载FlashDriver"
            self.message_signal.emit(tbMessage)
            print("len(flashDriverContent)=",len(flashDriverContent))
            print(" _maxNumOfBlockLen=", _maxNumOfBlockLen)
            while len(flashDriverContent) > _maxNumOfBlockLen:                                  # 传输Flash Driver数据
                # print("数据长度",len(flashDriverContent))
                self.uds_client.transfer_data(sequence_number=_blockSequenceCounter, data=flashDriverContent[0:(_maxNumOfBlockLen - 2)])
                _blockSequenceCounter += 1
                _blockSequenceCounter & 0xFF
                flashDriverContent = flashDriverContent[(_maxNumOfBlockLen - 2):]
            self.uds_client.transfer_data(sequence_number=_blockSequenceCounter, data=flashDriverContent)     # 传输Flash Driver剩余数据
            self.REFRESH_VALUE = 25
            self.value_signal.emit(self.REFRESH_VALUE)

            print("Flash Driver数据传输结束。")
            tbMessage = "软件刷写：下载数据阶段-FlashDriver传输结束"
            self.message_signal.emit(tbMessage)

            self.uds_client.request_transfer_exit(b'\x49')                                                           # 传输结束
            self.REFRESH_VALUE = 27
            self.value_signal.emit(self.REFRESH_VALUE)

            #检查编程完整性
            print("检查编程完整性")
            tbMessage = "软件刷写：下载数据阶段-检查编程完整性"
            self.message_signal.emit(tbMessage)
            flashDriverData = self.getFileContentInt(FlashPath)
            flashCrcValue = self.Calculate_CRC16_DNP(flashDriverSize, flashDriverData)
            print("flashCrcValue={}".format(flashCrcValue))
            flashCrcValueBytes = (flashCrcValue).to_bytes(4, byteorder="big")
            self.uds_client.start_routine(routine_id=0x0202, data=flashCrcValueBytes)
            self.REFRESH_VALUE = 30
            self.value_signal.emit(self.REFRESH_VALUE)

            #写入指纹信息
            print("开始写入指纹信息")
            tbMessage = "软件刷写：下载数据阶段-写入指纹信息"
            self.message_signal.emit(tbMessage)
            fringPrintInfo = (0x17,0x4,0x14,0x1,0x2,0x3,0x4,0x5,0x6)
            self.uds_client.write_data_by_identifier(did = 0xF15A, value = fringPrintInfo)
            self.REFRESH_VALUE = 32
            self.value_signal.emit(self.REFRESH_VALUE)

            # e:删除刷写的现有APP的内容
            print("开始删除现有APP内容。")
            tbMessage = "软件刷写：下载数据阶段-擦除现有APP内容"
            self.message_signal.emit(tbMessage)
            # AppSize, AppStartAddress = self.getFileSizeAndAddress(AppPath)
            # 获取APP的起始地址大小
            appHex = HexHandle(AppPath)
            appHexInfo = appHex.get_res()
            appStartAddress = appHexInfo["start_index"]
            appSize = appHexInfo["data_length"]
            addressAndSize = (0x44<<64)|(appStartAddress<<32) | appSize
            print("addressAndSize",addressAndSize)
            _bootswmemaddr1 = (addressAndSize).to_bytes(9, byteorder="big", signed=True)                      # 获取删除起始地址和大小
            print("_bootswmemaddr1",_bootswmemaddr1)
            self.uds_client.start_routine(routine_id=0xFF00, data=_bootswmemaddr1)
            self.REFRESH_VALUE = 35
            self.value_signal.emit(self.REFRESH_VALUE)

            # f1:请求下载APP 注意hex文件里面地址必须连续，中间不能空地址，比如.ld文件要对齐，text段的末尾加align 8对齐
            print("请求下载APP。")
            tbMessage = "软件刷写：下载数据阶段-请求下载APP"
            self.message_signal.emit(tbMessage)
            # appSize = self.getFileSize(AppPath)                                            # 获取APP的大小
            # print("appSize", appSize)
            appML = MemoryLocation(address=appStartAddress, memorysize=appSize)                     # APP的大小和地址
            print("appML", appML)
            appContent = self.getFileContent(AppPath)                                      # 获取APP的内容
            # print("appContent", appContent)
            resp_app = self.uds_client.request_download(memory_location=appML)                  # 请求下载0x34
            # _maxNumOfBlockLenApp = ((resp_app.data[1] << 8) | (resp_app.data[2] & 0xFF))         # 获取每次能传输的最大字节
            _maxNumOfBlockLenApp = 0x80
            print("_maxNumOfBlockLenApp", _maxNumOfBlockLenApp)
            bs = _maxNumOfBlockLenApp - 2
            # align with 8 bytes
            if(bs & 0x07):
                bs -= (bs & 0x07)
            print("bs", bs)

            _blockSequenceCounterApp = 1
            i = 0
            # f2:下载APP
            print("开始传输APP数据。")
            tbMessage = "软件刷写：下载数据阶段-下载APP"
            self.message_signal.emit(tbMessage)
            increase_value = round(40/(len(appContent)/(bs)),2)
            print("increase_value",increase_value)

            while len(appContent) > _maxNumOfBlockLenApp:                                        # 传输APP数据
                # print("数据长度", len(appContent))
                self.uds_client.transfer_data(sequence_number=_blockSequenceCounterApp, data=appContent[0:(bs)])

                i = i+1
                self.REFRESH_VALUE = round(35+increase_value*i)
                # print("self.REFRESH_VALUE",self.REFRESH_VALUE)
                self.value_signal.emit(self.REFRESH_VALUE)

                _blockSequenceCounterApp += 1
                _blockSequenceCounterApp & 0xFF
                if _blockSequenceCounterApp > 0xFF:
                    _blockSequenceCounterApp = 0x0
                appContent = appContent[(bs):]
                # time.sleep(0.05)
            self.uds_client.transfer_data(sequence_number=_blockSequenceCounterApp,
                                         data=appContent)                                        # 传输APP剩余数据

            self.REFRESH_VALUE = 80
            self.value_signal.emit(self.REFRESH_VALUE)

            # f3:下载APP结束
            print("APP数据传输结束。")
            tbMessage = "软件刷写：下载数据阶段-APP下载结束"
            self.message_signal.emit(tbMessage)
            self.uds_client.request_transfer_exit(b'\xD3')                                               # 传输结束
            self.REFRESH_VALUE = 82
            self.value_signal.emit(self.REFRESH_VALUE)

            # g:Check Programming Dependencies
            print("校验APP数据。")
            tbMessage = "软件刷写：下载数据阶段-校验APP数据"
            self.message_signal.emit(tbMessage)
            appSize, appDataAdd = self.getFileSizeAndAddress(AppPath)
            print("appSize", appSize)
            appData = self.getFileContentInt(AppPath)
            # print("appData", appData)

            crcvalue = self.Calculate_CRC16_DNP(appSize, appData)                                    # 获取CRC校验值
            print("crcvalue", crcvalue, type(crcvalue))
            crc_value = (crcvalue).to_bytes(4, byteorder="big")                      # 转换为bytes
            print("crc_value", crc_value)
            self.uds_client.start_routine(routine_id=0x0202, data=crc_value)
            # print("addressAndSize",addressAndSize)
            # addressAndSize2 = (addressAndSize << 16) | crcvalue
            # print("addressAndSize2",addressAndSize2)
            # _bootswmemaddr2 = (addressAndSize2).to_bytes(10, byteorder="big")
            # print("_bootswmemaddr2",_bootswmemaddr2)
            # self.uds_client.start_routine(routine_id=0xFF01, data=_bootswmemaddr2)
            self.REFRESH_VALUE = 85
            self.value_signal.emit(self.REFRESH_VALUE)

            # h:CheckApplication Program Validation
            print("验证APP数据有效性。")
            tbMessage = "软件刷写：下载数据阶段-验证APP有效性"
            self.message_signal.emit(tbMessage)
            self.uds_client.start_routine(routine_id=0xFF01)
            self.REFRESH_VALUE = 87
            self.value_signal.emit(self.REFRESH_VALUE)

            # i:重启ECU
            print("重启ECU")
            tbMessage = "软件刷写：下载数据阶段-ECU重启"
            self.message_signal.emit(tbMessage)
            self.uds_client.ecu_reset(1)
            self.REFRESH_VALUE = 90
            self.value_signal.emit(self.REFRESH_VALUE)

            time.sleep(1)

            # # III:刷新后处理
            # print("进入扩展模式")
            # tbMessage = "软件刷写：刷新后处理阶段-进入扩展模式"
            # self.message_signal.emit(tbMessage)
            # self.uds_client.change_session(3)
            # self.REFRESH_VALUE = 92
            # self.value_signal.emit(self.REFRESH_VALUE)

            # # j:开启通讯
            # print("开启通讯")
            # tbMessage = "软件刷写：刷新后处理阶段-恢复正常报文收发"
            # self.message_signal.emit(tbMessage)
            # self.uds_client.communication_control(0x0, 0x3)
            # self.REFRESH_VALUE = 94
            # self.value_signal.emit(self.REFRESH_VALUE)

            # # k:允许DTC
            # print("允许DTC")
            # tbMessage = "软件刷写：刷新后处理阶段-允许DTC检出"
            # self.message_signal.emit(tbMessage)
            # self.uds_client.control_dtc_setting(services.ControlDTCSetting.SettingType.on)
            # self.REFRESH_VALUE = 96
            # self.value_signal.emit(self.REFRESH_VALUE)

            # # # l:清除DTC
            # print("清除DTC")
            # tbMessage = "软件刷写：刷新后处理阶段-清除DTC"
            # self.message_signal.emit(tbMessage)
            # self.uds_client.clear_dtc(group=0xFFFFFF)
            # self.REFRESH_VALUE = 97
            # self.value_signal.emit(self.REFRESH_VALUE)

            # # m:进入正常模式
            # print("进入正常模式")
            # tbMessage = "软件刷写：刷新后处理阶段-进入正常模式"
            # self.message_signal.emit(tbMessage)
            # self.uds_client.change_session(1)
            # self.REFRESH_VALUE = 98
            # self.value_signal.emit(self.REFRESH_VALUE)

            # #检查硬件版本
            # print("检查硬件版本")
            # # 读取硬件版本
            # try:
            #     resp = self.uds_client.read_data_by_identifier(0xF193)
            #     UDS_str = resp.service_data.values[0xF193]
            #     print('UDS发送请求成功')
            #     # 硬件版本号
            #     self.message_signal.emit("刷写检查：读取硬件版本号如下：")
            #     self.message_signal.emit(UDS_str)
            # except:
            #     print('UDS发送请求失败')
            #     self.message_signal.emit('零件硬件版本读取失败!')

            # #读取软件版本
            # try:
            #     resp = self.uds_client.read_data_by_identifier(0xF195)
            #     UDS_str = resp.service_data.values[0xF195]
            #     print('UDS发送请求成功')
            #     # 软件版本号
            #     self.message_signal.emit("刷写检查：读取内部软件版本号如下：")
            #     self.message_signal.emit(UDS_str)
            # except:
            #     self.message_signal.emit('内部软件版本读取失败!')

            # #检查boot版本
            # try:
            #     resp = self.uds_client.read_data_by_identifier(0xF180)
            #     UDS_str = resp.service_data.values[0xF180]
            #     print('UDS发送请求成功')
            #     # boot软件版本号
            #     self.message_signal.emit("刷写检查：读取BOOT软件版本号如下：")
            #     self.message_signal.emit(UDS_str)
            # except:
            #     self.message_signal.emit('BOOT软件版本读取失败!')

            # n:刷新完成
            print("刷新完成！")
            tbMessage = "软件刷写：刷新后处理阶段-软件刷新完成"
            self.message_signal.emit(tbMessage)
            self.REFRESH_VALUE = 100
            self.value_signal.emit(self.REFRESH_VALUE)

            # 关闭连接
            self.connection.close()

        except Exception as err:
            print(err)
            tbMessage = err
            self.message_signal.emit("提示：发生错误，请重新连接PCAN或重启软件！")

if __name__ == '__main__':
    app = qw.QApplication(sys.argv)
    w = myMainWindow()
    w.show()
    sys.exit(app.exec_())
